package com.asurplus.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.asurplus.common.config.quartz.QuartzManager;
import com.asurplus.common.enums.BackupCategoryEnum;
import com.asurplus.common.utils.MysqlTool;
import com.asurplus.common.utils.RES;
import com.asurplus.common.vo.BackupJobVO;
import com.asurplus.common.vo.BackupReqVO;
import com.asurplus.common.vo.LayuiTablePojo;
import com.asurplus.entity.BackupLog;
import com.asurplus.entity.BackupTask;
import com.asurplus.entity.NodeInfo;
import com.asurplus.entity.ZoneInfo;
import com.asurplus.mapper.BackupTaskMapper;
import com.asurplus.mapper.NodeInfoMapper;
import com.asurplus.mapper.ZoneInfoMapper;
import com.asurplus.service.BackupLogService;
import com.asurplus.service.NodeInfoService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.CronExpression;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @since 2022-08-04
 */
@Slf4j
@Service
public class NodeInfoServiceImpl extends ServiceImpl<NodeInfoMapper, NodeInfo> implements NodeInfoService {

    @Resource
    private ZoneInfoMapper zoneInfoMapper;
    @Autowired
    private MysqlTool mysqlTool;
    @Resource
    private BackupTaskMapper backupTaskMapper;
    @Autowired
    private BackupLogService backupLogService;
    @Resource
    private QuartzManager quartzManager;

    @Override
    public LayuiTablePojo list(Integer page, Integer limit, NodeInfo reqVO) {
        LambdaQueryWrapper<NodeInfo> queryWrapper = new LambdaQueryWrapper<>();
        if (null != reqVO.getZoneId()) {
            queryWrapper.eq(NodeInfo::getZoneId, reqVO.getZoneId());
        }
        if (StringUtils.isNotBlank(reqVO.getName())) {
            queryWrapper.like(NodeInfo::getName, reqVO.getName());
        }
        if (StringUtils.isNotBlank(reqVO.getHost())) {
            queryWrapper.like(NodeInfo::getHost, reqVO.getHost());
        }
        if (StringUtils.isNotBlank(reqVO.getPort())) {
            queryWrapper.like(NodeInfo::getPort, reqVO.getPort());
        }
        queryWrapper.orderByDesc(NodeInfo::getCreateTime);
        Page<NodeInfo> nodeInfoPage = this.baseMapper.selectPage(new Page<>(page, limit), queryWrapper);
        if (CollectionUtil.isNotEmpty(nodeInfoPage.getRecords())) {
            for (NodeInfo item : nodeInfoPage.getRecords()) {
                item.setPassword("********");
            }
        }
        return LayuiTablePojo.ok(nodeInfoPage);
    }

    @Override
    public RES add(NodeInfo nodeInfo) {
        LambdaQueryWrapper<NodeInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(NodeInfo::getName, nodeInfo.getName());
        int count = this.count(queryWrapper);
        if (0 < count) {
            return RES.no("连接名已存在");
        }
        ZoneInfo zoneInfo = zoneInfoMapper.selectById(nodeInfo.getZoneId());
        nodeInfo.setZoneName(zoneInfo.getName());
        this.baseMapper.insert(nodeInfo);
        return RES.ok();
    }

    @Override
    public RES update(NodeInfo nodeInfo) {
        LambdaQueryWrapper<NodeInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ne(NodeInfo::getId, nodeInfo.getId());
        queryWrapper.eq(NodeInfo::getName, nodeInfo.getName());
        int count = this.count(queryWrapper);
        if (0 < count) {
            return RES.no("连接名已存在");
        }
        ZoneInfo zoneInfo = zoneInfoMapper.selectById(nodeInfo.getZoneId());
        nodeInfo.setZoneName(zoneInfo.getName());
        this.baseMapper.updateById(nodeInfo);
        return RES.ok();
    }

    @Override
    public RES delete(Integer id) {
        this.baseMapper.deleteById(id);
        return RES.ok();
    }

    @Override
    public RES saveBackUp(BackupReqVO reqVO) {
        if (null == reqVO.getNodeId()) {
            return RES.no("备份信息错误，请刷新后重试");
        }
        if (StringUtils.isBlank(reqVO.getDatabase())) {
            return RES.no("请选择需要备份的数据库");
        }
        NodeInfo nodeInfo = this.baseMapper.selectById(reqVO.getNodeId());
        if (null == nodeInfo) {
            return RES.no("备份信息错误，请刷新后重试");
        }
        // 组装备份参数
        BackupJobVO jobVO = getBackupJobVO(nodeInfo, reqVO);
        try {
            // 立即备份
            if (reqVO.getCategoryEnum().equals(BackupCategoryEnum.MANUAL)) {
                // 保存备份记录
                BackupLog backupLog = backupLogService.saveBackupLog(jobVO, BackupCategoryEnum.MANUAL);
                // 调用备份
                mysqlTool.saveBackUp(jobVO, backupLog);
                return RES.ok("操作成功，请稍后在【备份记录】中查看");
            }
            // 定时备份
            else {
                if (StringUtils.isBlank(reqVO.getCron())) {
                    return RES.no("请输入cron表达式");
                }
                if (!CronExpression.isValidExpression(reqVO.getCron())) {
                    return RES.no("请输入正确的cron表达式");
                }
                BackupTask backupTask = new BackupTask();
                backupTask.setNodeId(reqVO.getNodeId());
                backupTask.setCron(reqVO.getCron());
                backupTask.setStatus(reqVO.getStatus());
                backupTask.setDatabaseName(reqVO.getDatabase());
                backupTask.setTablesName(StringUtils.join(reqVO.getTables(), ","));
                backupTask.setDataType(reqVO.getDataType());
                backupTask.setRemark(reqVO.getRemark());
                // 定时任务参数
                backupTask.setParam(jobVO);
                backupTaskMapper.insert(backupTask);
                // 添加定时任务
                quartzManager.add(backupTask.getId(), backupTask.getCron(), JSON.toJSONString(backupTask.getParam()), backupTask.getStatus());
                return RES.ok("操作成功，请在【任务管理】中查看");
            }
        } catch (Exception e) {
            return RES.no("数据库备份失败：" + e.getMessage());
        }
    }

    /**
     * 组装备份参数
     */
    public BackupJobVO getBackupJobVO(NodeInfo nodeInfo, BackupReqVO reqVO) {
        BackupJobVO backupJobVO = new BackupJobVO();
        backupJobVO.setNodeId(nodeInfo.getId());
        backupJobVO.setHost(nodeInfo.getHost());
        backupJobVO.setPort(nodeInfo.getPort());
        backupJobVO.setUsername(nodeInfo.getUsername());
        backupJobVO.setPassword(nodeInfo.getPassword());
        backupJobVO.setDatabase(reqVO.getDatabase());
        backupJobVO.setTables(reqVO.getTables());
        backupJobVO.setDataType(reqVO.getDataType());
        backupJobVO.setIsCompress(reqVO.getIsCompress());
        backupJobVO.setIsUpload(reqVO.getIsUpload());
        backupJobVO.setIsDelete(reqVO.getIsDelete());
        return backupJobVO;
    }

    @Override
    public List<NodeInfo> listSelect(Integer zoneId) {
        LambdaQueryWrapper<NodeInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(NodeInfo::getId, NodeInfo::getName);
        if (null != zoneId) {
            queryWrapper.eq(NodeInfo::getZoneId, zoneId);
        }
        queryWrapper.orderByAsc(NodeInfo::getName);
        return this.baseMapper.selectList(queryWrapper);
    }
}
